#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>

#define PI 3.14159

using namespace std;


class source{

    private:

        // location of the light source
        double x,y,z;
        // magnitude of the light source
        double magnitude;
        // lamda wave length
        double lamda;

    public:
        source(double _x, double _y, double _z, double _magnitude, double _lamda){
            x = _x;
            y = _y;
            z = _z;
            magnitude = _magnitude;
            lamda = _lamda;
        }

        double getX(){
            return x;
        }

        double getY(){
            return y;
        }

        double getZ(){
            return z;
        }

        double getMagnitude(){
            return magnitude;
        }

        double getLamda(){
            return lamda;
        }
};


class panel{

    private:

        double **data;
        double z;
        int range;
        double distance;

    public:
        panel(double _z, int _range, double _distance){
            z = _z;
            range = _range;
            distance = _distance;
            data = new double*[range];

            for (int i = 0; i < range; i++){
                data[i] = new double[range];
            }

            for (int i = 0; i < range; i++){
                for (int j = 0; j < range; j++){
                    data[i][j] = 0;
                }
            }
        }

        ~panel(){

            ofstream output("interfere.txt");
            for (int i = 0; i < range; i++){
                for (int j = 0; j < range; j++){
                    output << data[i][j] << "\t";
                }
                output << endl;
            }
            output.close();

            for (int i = 0; i < range; i++){
                delete []data[i];
            }

            delete []data;
            data = NULL;
        }

        double getData(int i, int j){
            return data[i][j];
        }

        void setData(int i, int j, double _value){
            data[i][j] = _value;
        }

        double indexToMeter(int index){
            int midIndex = (range - 1) / 2;
            return (index - midIndex) * distance;
        }

        int meterToIndex(double meter){
            int midIndex = (range - 1) / 2;
            return  round((meter / distance)  + midIndex + 0.5);
        }

        int getRange(){
            return range;
        }

        double getZ(){
            return z;
        }
};


class OpticalSystem{

    private:
        panel *pa;
        source *s1;
        source *s2;
        source *s3;
        source *s4;


    public:
        OpticalSystem(){
            pa = new panel(0.2, 401, 0.25e-4);
            s1 = new source(0.0002, 0, 0, 1, 5.0e-7);
            s2 = new source(-0.0002, 0, 0, 1, 5.0e-7);
            s3 = new source(0, 0.0002, 0, 1, 5.0e-7);
            s4 = new source(0, -0.0002, 0, 1, 5.0e-7);

        }

        int Run(){
            for (int i = 0; i < pa->getRange(); i++){
                for (int j = 0; j < pa->getRange(); j++){
                    double r;
                    double E1, E2, E3, E4;
                    double dx,dy,dz;
                    dz = pa->getZ() - s1->getZ();
                    dx = pa->indexToMeter(i) - s1->getX();
                    dy = pa->indexToMeter(j) - s1->getY();
                    r = sqrt(dx * dx + dy * dy + dz * dz);

                    E1 = s1->getMagnitude() * cos(2 * PI * r / s1->getLamda()) / r;

                    dz = pa->getZ() - s2->getZ();
                    dx = pa->indexToMeter(i) - s2->getX();
                    dy = pa->indexToMeter(j) - s2->getY();

                    r = sqrt(dx * dx + dy * dy + dz * dz);
                    E2 = s2->getMagnitude() * cos(2 * PI * r / s2 ->getLamda()) / r;

                    dz = pa->getZ() - s3->getZ();
                    dx = pa->indexToMeter(i) - s3->getX();
                    dy = pa->indexToMeter(j) - s3->getY();

                    r = sqrt(dx * dx + dy * dy + dz * dz);
                    E3 = s3->getMagnitude() * cos(2 * PI * r / s3 ->getLamda()) / r;

                    dz = pa->getZ() - s4->getZ();
                    dx = pa->indexToMeter(i) - s4->getX();
                    dy = pa->indexToMeter(j) - s4->getY();

                    r = sqrt(dx * dx + dy * dy + dz * dz);
                    E4 = s4->getMagnitude() * cos(2 * PI * r / s4 ->getLamda()) / r;




                    pa->setData(i, j, E1 + E2 +E3 + E4);
                }
            }
        }

        ~OpticalSystem(){
            delete pa;
            delete s1;
            delete s2;
            delete s3;
            delete s4;
        }
};


int main(){
    OpticalSystem *s = new OpticalSystem();
    s->Run();
    delete s;
    return 0;
}
